/**
 * FormFieldTree
 */
layui.define(['FormField', 'yunj', 'jquery'], function (exports) {

    let FormField = layui.FormField;
    let win = window;
    let doc = document;
    let $ = layui.jquery;

    class FormFieldTree extends FormField {

        constructor(options = {}) {
            super(options);
            this.mode = null;                  // 模式
            this.allOptional = null;          // 是否所有可选
            this.retractLevel = null;         // 是否所有可选
            this.nodes = null;
            this.nodeIdxMap = null;           // 节点id与对应下标的映射关系
            this.show_box_el = null;
            this.txt_box_el = null;
            this.icon_el = null;
            this.filter_box_el = null;
            this.filter_tree_el = null;
            this.ztree = null;
        }

        defineExtraArgs() {
            let that = this;
            return {
                mode: "checkbox",
                nodes: [],
                allOptional: false,
                retractLevel: -1,
                disabled: false
            };
        }

        handleArgs(args) {
            switch (args.mode) {
                case "checkbox":
                    if (args.verify.indexOf("arrayIn") === -1)
                        args.verify += (args.verify ? "|" : "") + `arrayIn:${yunj.arrayColumn(args.nodes, "id").join(",")}`;
                    break;
                case "radio":
                    if (args.verify.indexOf("in") === -1)
                        args.verify += (args.verify ? "|" : "") + `in:${yunj.arrayColumn(args.nodes, "id").join(",")}`;
                    break;
            }
            return args;
        }

        defineBoxHtml() {
            let that = this;
            return `<div class="layui-form-item yunj-form-item yunj-form-tree" id="${that.id}">__layout__</div>`;
        }

        layoutControl() {
            let that = this;
            let controlHtml = `<div class="show-box">
                                    <div class="txt-box" data-ids=""></div>
                                    <i class="layui-icon layui-icon-triangle-d"></i>
                                </div><div class="filter-box"><ul class="filter-tree ztree"></ul></div>`;
            return `<div class="layui-input-inline yunj-form-item-control">${controlHtml}</div>`;
        }

        async renderBefore() {
            let that = this;
            that.mode = that.args.mode;
            that.allOptional = that.args.allOptional;
            that.retractLevel = that.args.retractLevel;
            that.setNodes();
            win.jQuery = $;
            await yunj.includeCss('/static/yunj/libs/zTree_v3/css/metroStyle/metroStyle.css');
            await yunj.includeJs('/static/yunj/libs/zTree_v3/js/jquery.ztree.core.js');
            await yunj.includeJs('/static/yunj/libs/zTree_v3/js/jquery.ztree.excheck.js');
            await yunj.includeJs('/static/yunj/libs/zTree_v3/js/jquery.ztree.exedit.js');
            return 'done';
        }

        // 获取节点等级
        getNodeLevel(nodeId, nodes) {
            let that = this;
            let nodeIdxMap = that.nodeIdxMap;
            if (!nodeIdxMap.has(nodeId)) return 0;
            let idx = nodeIdxMap.get(nodeId);
            let node = nodes[idx];
            if (node.hasOwnProperty("level")) return node.level;
            if (!node.pid || node.pid === "0")
                node.level = 0;
            else
                node.level = that.getNodeLevel(node.pid, nodes) + 1;
            return node.level;
        }

        setNodes() {
            let that = this;
            let nodes = that.args.nodes;
            let nodeMap = new Map();
            let l = nodes.length;
            for (let i = 0; i < l; i++) {
                // id string
                nodes[i].id = nodes[i].id.toString();
                let node = nodes[i];
                let id = node.id;
                nodeMap.set(id, i);
                // 展开
                nodes[i].open = true;
                // 是否可选
                if (that.allOptional) continue;
                let nocheck = false;
                for (let j = 0; j < l; j++) {
                    if (id !== nodes[j].pid.toString()) continue;
                    nocheck = true;
                    break;
                }
                nodes[i].nocheck = nocheck;
            }
            that.nodeIdxMap = nodeMap;
            // 判断是否收起 retractLevel
            if (that.retractLevel >= 0) {
                nodes.forEach(node => {
                    let nodeLevel = that.getNodeLevel(node.id, nodes);
                    node.open = nodeLevel < that.retractLevel;
                });
            }
            that.nodes = nodes;
        }

        renderDone() {
            let that = this;
            that.show_box_el = that.fieldBoxEl.find('.show-box');
            that.txt_box_el = that.fieldBoxEl.find('.show-box .txt-box');
            that.icon_el = that.fieldBoxEl.find('.layui-icon-triangle-d');
            that.filter_box_el = that.fieldBoxEl.find('.filter-box');
            that.filter_tree_el = that.fieldBoxEl.find('.filter-box .filter-tree');
        }

        setValue(val = '') {
            let that = this;
            if (yunj.isScalar(val) && val)
                val = that.mode === "radio" ? [val]
                    : (yunj.isJson(val) ? JSON.parse(val) : (yunj.isString(val) && val.indexOf(",") !== -1 ? val.split(",") : [val]));
            val = yunj.isArray(val) ? val : [];
            let ids = JSON.parse(JSON.stringify(val));
            val = [];
            let valTxt = "";
            for (let i = 0, l = ids.length; i < l; i++) {
                let id = ids[i].toString();
                if (!that.nodeIdxMap.has(id)) continue;
                let idx = that.nodeIdxMap.get(id);
                val.push(id);
                valTxt += `、${that.nodes[idx].name}`;
            }
            if (valTxt.length > 0) valTxt = valTxt.substr(1);
            that.txt_box_el.data("ids", JSON.stringify(val));
            that.txt_box_el.html(valTxt);
        }

        getValue() {
            let that = this;
            let ids = that.txt_box_el.data("ids");
            ids = JSON.parse(ids);
            if (ids.length <= 0) return "";
            return that.mode === 'radio' ? ids[0] : ids;
        }

        // 展开筛选
        open_filter_box() {
            let that = this;
            that.icon_el.removeClass('icon-down').addClass('icon-up').css({"transform": `rotate(180deg)`});
            let top = that.show_box_el.offset().top + that.show_box_el.outerHeight() - $(win).scrollTop();
            // 上下定位
            if (top + 300 > $(win).height() && top >= 300) {
                that.filter_box_el.css({'top': '', 'bottom': '42px'});
            } else {
                that.filter_box_el.css({'top': '42px', 'bottom': ''});
            }
            if (that.filter_tree_el.html().length <= 0) that.render_filter_tree();
            that.filter_box_el.show();
        }

        render_filter_tree() {
            let that = this;
            let ids = that.txt_box_el.data("ids");
            ids = ids.length >= 0 ? JSON.parse(ids) : [];
            let nodes = that.nodes;
            for (let i = 0, l = ids.length; i < l; i++) {
                let id = ids[i];
                if (!that.nodeIdxMap.has(id)) continue;
                let idx = that.nodeIdxMap.get(id);
                nodes[idx].checked = true;
            }
            let setting = {
                view: {
                    showIcon: false,
                },
                check: {
                    enable: true,
                },
                data: {
                    simpleData: {
                        enable: true,
                        pIdKey: "pid",
                    }
                },
                callback: {
                    onClick: function (e, treeId, tree_node, clickFlag) {
                        that.ztree.checkNode(tree_node, !tree_node.checked, true);
                        let nodes = that.ztree.getCheckedNodes(true);
                        let val = [];
                        for (let i = 0; i < nodes.length; i++) {
                            val.push(nodes[i].id);
                        }
                        that.setValue(val);
                    },
                    onCheck: function (e, treeId, tree_node) {
                        let nodes = that.ztree.getCheckedNodes(true);
                        let val = [];
                        for (let i = 0; i < nodes.length; i++) {
                            val.push(nodes[i].id);
                        }
                        that.setValue(val);
                    }
                }
            };
            switch (that.mode) {
                case "radio":
                    setting.check.chkStyle = "radio";
                    setting.check.radioType = "all";
                    break;
            }
            that.ztree = $.fn.zTree.init(that.filter_tree_el, setting, that.nodes);
        }

        // 关闭筛选
        close_filter_box() {
            let that = this;
            that.icon_el.removeClass('icon-up').addClass('icon-down').css({"transform": `rotate(0deg)`});
            that.filter_box_el.hide();
        }

        defineExtraEventBind() {
            let that = this;

            $(doc).on('click', function (e) {
                if (!that.filter_box_el.is(e.target) && that.filter_box_el.has(e.target).length === 0 &&
                    !that.show_box_el.is(e.target) && that.show_box_el.has(e.target).length === 0)
                    that.close_filter_box();
            });

            that.fieldBoxEl.on('click', '.txt-box', function (e) {
                if (that.args.disabled) return false;
                let isOpen = that.icon_el.hasClass('icon-down') || (!that.icon_el.hasClass('icon-down') && !that.icon_el.hasClass('icon-up'));
                if (isOpen) {
                    that.open_filter_box();
                } else {
                    that.close_filter_box();
                }
                e.stopPropagation();
            });

        }

    }

    exports('FormFieldTree', FormFieldTree);
});